/**
* @file drv_flash.c
* @brief  qspi flash
* @details 
* @author huangbin(QQ:405803242)
* @email huangembed@163.com
* @version V1.0.0
* @date 2025-04-20
* @copyright All documents are copyrighted by Shenzhen Xinlongwei Technology Co., LTD.
*            They may not be used for commercial purposes without permission
*/
#include "inc.h"
#include "drv_qspi_flash.h"
#include "Flash_Info.h"
#include "drv_qspi.h"

struct
{
	uint8_t state;
	uint8_t *buf;
	uint32_t buf_pos;
	uint32_t buf_len;
}qspi_trans;
extern QSPI_ComConfig_InitTypeDef  QSPI_ComConfig_InitStructure;
//flash直接操作，读写数据模式
typedef enum
{
    FLASH_TRANS_TYPE_POLL = 0, //状态轮询方式
    FLASH_TRANS_TYPE_DMA = 1, //dma方式读写
    FLASH_TRANS_TYPE_FIFO = 2, //中断方式
}TRANS_TYPE_e;

void Flash_Indirect_Operation(const Flash_CMD_t *cmd, uint32_t addr, uint8_t *buf, uint32_t len,uint8_t Trans_Type)
{
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode     = cmd->DoubleDataRateMode;//DDR模式使能
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode       = cmd->Instruction_Mode;//指令模式 无/单线/双线/四线传输指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins         = cmd->Instruction ;//具体指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode      = cmd->Address_Mode;//地址模式 无/单线/双线/四线传输地址
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize      = cmd->Address_Size;//地址长度 8/16/24/32
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode      = cmd->Alternate_Bytes_Mode;//交替字节模式 无/单线/双线/四线传输交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABSize      = cmd->Alternate_Bytes_Size;//交替字节长度 8/16/24/32 位交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode       = cmd->Data_Mode;//数据模式 无/单线/双线/四线传输数据
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode       = cmd->Functional_Mode;//功能模式 间接写/间接读/自动轮询/内存映射
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = cmd->Dummy_Cycles;//空指令周期数 0~31
	
	while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == SET)  __NOP();

	if(len == 0)
		len = 1;
	
	if(cmd->Data_Mode != QSPI_ComConfig_DMode_NoData)
		QSPI_SetDataLength(len - 1);
	QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
	if(cmd->Address_Mode != QSPI_ComConfig_ADMode_NoAddress)
		QSPI_SetAddress(addr);
	if(cmd->Data_Mode != QSPI_ComConfig_DMode_NoData)
	{
		if(Trans_Type == 1) //DMA
		{
			if(cmd->Functional_Mode == QSPI_ComConfig_FMode_Indirect_Write)
				QSPI_DMA_Send(buf,len);
			else
				QSPI_DMA_Recv(buf,len);
			
			while(DMA_GetFlagStatus(QSPI_DMA_FLAG_TC) == RESET);
			DMA_ClearFlag(QSPI_DMA_FLAG_TC);
			DMA_Cmd(QSPI_DMA_CHANNEL,DISABLE);
			QSPI_DMACmd(DISABLE);
		}
		else if(Trans_Type == 2) //FIFO interrupt
		{
			qspi_trans.buf = buf;
			qspi_trans.buf_pos = 0;
			qspi_trans.buf_len = len;
			if(cmd->Functional_Mode == QSPI_ComConfig_FMode_Indirect_Write)
				qspi_trans.state = 1;
			else
				qspi_trans.state = 2;
				QSPI_ITConfig(QSPI_IT_FT, ENABLE);
		}
		else //poll
		{
			if(cmd->Functional_Mode == QSPI_ComConfig_FMode_Indirect_Write)
			{
				for(uint16_t i = 0; i < len; )
				{
					while(QSPI_GetFlagStatus(QSPI_FLAG_FT) == RESET);
					QSPI_SendData32(*(uint32_t *)&buf[i]);
					i += 4;
				}
			}
			else
			{
				for(uint16_t i = 0; i < len;)
				{
					while(QSPI_GetFlagStatus(QSPI_FLAG_FT) == RESET);
					*(uint32_t *)&buf[i] = QSPI_ReceiveData32();
					i += 4;
				}
			}
		}
	}
}
void Flash_Auto_Polling_Operation(const Flash_CMD_t *cmd, uint32_t QSPI_Match, uint32_t QSPI_Mask , uint32_t QSPI_Match_Mode, uint8_t AutoStop,uint32_t len,uint32_t addr)
{
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode     = cmd->DoubleDataRateMode;//DDR模式使能
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode       = cmd->Instruction_Mode;//指令模式 无/单线/双线/四线传输指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins         = cmd->Instruction ;//具体指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode      = cmd->Address_Mode;//地址模式 无/单线/双线/四线传输地址
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize      = cmd->Address_Size;//地址长度 8/16/24/32
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode      = cmd->Alternate_Bytes_Mode;//交替字节模式 无/单线/双线/四线传输交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABSize      = cmd->Alternate_Bytes_Size;//交替字节长度 8/16/24/32 位交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode       = cmd->Data_Mode;//数据模式 无/单线/双线/四线传输数据
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode       = QSPI_ComConfig_FMode_Auto_Polling;//功能模式 间接写/间接读/自动轮询/内存映射
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = cmd->Dummy_Cycles;//空指令周期数 0~31
	
	if(len == 0)
		len = 1;
	
	while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == SET)  __NOP();
	if(cmd->Data_Mode != QSPI_ComConfig_DMode_NoData)
		QSPI_SetDataLength(len - 1);
	if(cmd->Address_Mode != QSPI_ComConfig_ADMode_NoAddress)
		QSPI_SetAddress(addr);
	QSPI_AutoPollingMode_Config(QSPI_Match,QSPI_Mask,QSPI_Match_Mode);
	if(AutoStop)
		QSPI_AutoPollingModeStopCmd(ENABLE);
	else
		QSPI_AutoPollingModeStopCmd(DISABLE);
	QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
	while(QSPI_GetFlagStatus(QSPI_FLAG_SM) != SET) __NOP();
	if(!AutoStop)
		QSPI_AbortRequest();
    while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == SET)  __NOP();
//	while(QSPI_GetFlagStatus(QSPI_FLAG_SM) == SET);
//	if(!AutoStop)
//		QSPI_AbortRequest();
}
void Flash_Indirect_Cmd_Set(const Flash_CMD_t *cmd)
{
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode     = cmd->DoubleDataRateMode;//DDR模式使能
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode       = cmd->Instruction_Mode;//指令模式 无/单线/双线/四线传输指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins         = cmd->Instruction ;//具体指令
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode      = cmd->Address_Mode;//地址模式 无/单线/双线/四线传输地址
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize      = cmd->Address_Size;//地址长度 8/16/24/32
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode      = cmd->Alternate_Bytes_Mode;//交替字节模式 无/单线/双线/四线传输交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABSize      = cmd->Alternate_Bytes_Size;//交替字节长度 8/16/24/32 位交替字节
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode       = cmd->Data_Mode;//数据模式 无/单线/双线/四线传输数据
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode       = cmd->Functional_Mode;//功能模式 间接写/间接读/自动轮询/内存映射
	QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = cmd->Dummy_Cycles;//空指令周期数 0~31
	
	QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
}
void QSPI_M2M_DMA_Read(uint32_t Addr,uint8_t *buf,uint16_t len)
{
	DMA_Cmd(QSPI_M2M_DMA_CHANNEL,DISABLE);
	DMA_SetCurrDataCounter(QSPI_M2M_DMA_CHANNEL,len);
	QSPI_M2M_DMA_CHANNEL->CPAR = Addr;
	QSPI_M2M_DMA_CHANNEL->CMAR = (uint32_t)buf;
	DMA_Cmd(QSPI_M2M_DMA_CHANNEL,ENABLE);
}
//////////////////////////////////////api////////////////////////////////////////////////
void sFLASH_Init(void)
{
    uint32_t id;
    QSPI_Configuration();
    id = sFLASH_ReadID();
    sFLASH_Config_QE( (id >> 8) & 0x000000FF);
    sFLASH_Config_Driver();
}

/**
  * @brief  Erases the specified FLASH sector.4KB
  * @param  SectorAddr: address of the sector to erase.
  * @retval None
  */
void sFLASH_EraseSector(uint32_t SectorAddr)
{
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,FLASH_TRANS_TYPE_POLL);    
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_SECTOR_ERASE],SectorAddr,NULL,0,FLASH_TRANS_TYPE_POLL);
	Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x000000001,QSPI_PMM_AND,ENABLE,1,0);
}

/**
  * @brief  Erases the specified FLASH block.64KB
  * @param  SectorAddr: address of the block to erase.
  * @retval None
  */
void sFLASH_EraseBlock64K(uint32_t BlockAddr)
{
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,FLASH_TRANS_TYPE_POLL);    
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_BLOCK_ERASE],BlockAddr,NULL,0,FLASH_TRANS_TYPE_POLL);
	Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x00000001,QSPI_PMM_AND,ENABLE,1,0);
}

/**
  * @brief  Erases the entire FLASH.
  * @param  None
  * @retval None
  */
void sFLASH_EraseChip(void)
{
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,FLASH_TRANS_TYPE_POLL);    
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_CHIP_ERASE],0,NULL,0,FLASH_TRANS_TYPE_POLL);
	Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x00000001,QSPI_PMM_AND,ENABLE,1,0);
}

/**
  * @brief  Writes more than one byte to the FLASH with a single WRITE cycle 
  *         (Page WRITE sequence).
  * @note   The number of byte can't exceed the FLASH page size.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the FLASH.
  * @param  WriteAddr: FLASH's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the FLASH, must be equal
  *         or less than "sFLASH_PAGESIZE" value.
  * @retval None
  */
void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,FLASH_TRANS_TYPE_POLL);    
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_PAGE_PROG],WriteAddr,pBuffer,NumByteToWrite,FLASH_TRANS_TYPE_POLL);
    Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x00000001,QSPI_PMM_AND,ENABLE,1,0);
}

/**
  * @brief  Writes block of data to the FLASH. In this function, the number of
  *         WRITE cycles are reduced, using Page WRITE sequence.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the FLASH.
  * @param  WriteAddr: FLASH's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the FLASH.
  * @retval None
  */
void sFLASH_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint32_t Temp;
    
	uint32_t offset,firstbytes,page,endbytes;

	offset = WriteAddr % sFLASH_SPI_PAGESIZE;
	if(offset)	//非对齐地址，先写这一页数据
	{
		firstbytes = sFLASH_SPI_PAGESIZE - offset;	//data in current page
		if(firstbytes >= NumByteToWrite)
			firstbytes = NumByteToWrite;
		sFLASH_WritePage(pBuffer,WriteAddr,firstbytes);
		NumByteToWrite -= firstbytes;	//remain data
		pBuffer += firstbytes;		//set data offset
		WriteAddr += firstbytes;		//set address
	}
	if(NumByteToWrite) //
	{
		if(NumByteToWrite > sFLASH_SPI_PAGESIZE)	//over one page
		{
			page = NumByteToWrite / sFLASH_SPI_PAGESIZE;
			endbytes = NumByteToWrite - sFLASH_SPI_PAGESIZE * page;
			while(page--)
			{
				sFLASH_WritePage(pBuffer,WriteAddr,sFLASH_SPI_PAGESIZE);		//one page
				pBuffer += sFLASH_SPI_PAGESIZE;	
				WriteAddr += sFLASH_SPI_PAGESIZE;
			}
			if(endbytes)
				sFLASH_WritePage(pBuffer,WriteAddr,endbytes);
		}
		else //Less than a page or one page
		{
				sFLASH_WritePage(pBuffer,WriteAddr,NumByteToWrite);
		}
	}    
}
/**
  * @brief  Reads a block of data from the FLASH.
  * @param  pBuffer: pointer to the buffer that receives the data read from the FLASH.
  * @param  ReadAddr: FLASH's internal address to read from.
  * @param  NumByteToRead: number of bytes to read from the FLASH.
  * @retval None
  */
void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    Flash_CMD_t Temp_Flash_Cmd;
    uint32_t* p = (uint32_t *)pBuffer;
    
    memcpy(&Temp_Flash_Cmd,&Flash_Cmd[FLASH_CMD_QUAD_INOUT_FAST_READ],sizeof(Flash_CMD_t));
    Temp_Flash_Cmd.Functional_Mode = QSPI_ComConfig_FMode_Memory_Mapped;
    Flash_Indirect_Cmd_Set(&Temp_Flash_Cmd);   
//    DebugPrintf("[Flash] Xip bytes read!\r\n");
//按byte读取，不需要考虑对齐问题，兼容性好    
//    for(uint32_t i = 0; i < NumByteToRead; i++)
//    {
//        pBuffer[i] = *(uint8_t *)(QSPI_XIP_ADDR + ReadAddr + i);
//    }  
//按字读取， pBuffer和ReadAddr都必须对齐四字节地址
//    DebugPrintf("[Flash] Xip bytes read!\r\n");
//    for(uint32_t i = 0; i < NumByteToRead/4; i++)
//    {
//        *p++ = *(uint32_t *)(QSPI_XIP_ADDR + ReadAddr + i*4);
//    }
//DMA方式读
    QSPI_M2M_DMA_Read(QSPI_XIP_ADDR + ReadAddr,pBuffer,NumByteToRead);
    while(DMA_GetFlagStatus(QSPI_M2M_DMA_FLAG_TC) == RESET);
    DMA_ClearFlag(QSPI_M2M_DMA_FLAG_TC);
    DMA_Cmd(QSPI_M2M_DMA_CHANNEL,DISABLE);     
}
void sFLASH_ReadBufferWithXip(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    Flash_CMD_t Temp_Flash_Cmd;
    
    memcpy(&Temp_Flash_Cmd,&Flash_Cmd[FLASH_CMD_QUAD_INOUT_FAST_READ],sizeof(Flash_CMD_t));
    Temp_Flash_Cmd.Functional_Mode = QSPI_ComConfig_FMode_Memory_Mapped;
    Flash_Indirect_Cmd_Set(&Temp_Flash_Cmd);  

//按byte读取，不需要考虑对齐问题，兼容性好    
    for(uint32_t i = 0; i < NumByteToRead; i++)
    {
        pBuffer[i] = *(uint8_t *)(QSPI_XIP_ADDR + ReadAddr + i);
    }          
}
/**
  * @brief  Reads FLASH Manufacturer[bit15-bit8]/Device ID[bit7-bit0].
  * @param  None
  * @retval FLASH identification
  */
uint32_t sFLASH_ReadID(void)
{
	uint8_t Flash_ID[4];
    uint32_t Flash_Capcity;
    
    Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_READ_ID],0,Flash_ID,2,0);	
    Flash_Capcity = 2 << Flash_ID[1];
    
    DebugPrintf("[FLASH]NorFlash ID : 0x%02X%02X\r\n",Flash_ID[0], Flash_ID[1]);
	DebugPrintf("[FLASH]Manufacture : %s\r\n",Get_Flash_Manufature(Flash_ID[0]));
    DebugPrintf("[FLASH]Capcity : %d%s\r\n",Flash_Capcity >= 0x100000?(Flash_Capcity/0x100000):(Flash_Capcity/0x400),Flash_Capcity >= 0x100000?"MB":"KB");
    
    return Flash_ID[0] << 8 | Flash_ID[1];
}
bool sFLASH_Config_QE(uint8_t Manufactor)
{
    uint8_t State[3];
	switch(Manufactor)
	{
       case MANUFATOR_BY: //博雅
            Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS2],0,State,1,0);
            DebugPrintf("[FLASH]BOYA Status register 2 : %02X\r\n",State[0]);
            if((State[0] & 0x02) == 0) //确认QE位已经开启，非华邦芯片有QE位默认为0
            {
                State[0] |= 0x02;
                Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,0);
                Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_STATUS2],0,State,1,0);
                Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x00000001,QSPI_PMM_AND,ENABLE,1,0);
                Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS2],0,State,1,0);
                if((State[0] & 0x02) == 0)
                {
                    DebugPrintf("[FLASH]status register 2 write fail: %02X\r\n",State[0]);
                    return false;
                }
            }       
        break;
       default:
        Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS2],0,State,1,0);
        DebugPrintf("[FLASH]unknow Manufactor,status register 2: %02X\r\n",State[0]);
        if((State[0] & 0x02) == 0)
            return false;
        break;
    }
    return true;

}
//配置flash驱动输出能力最强，适配高速读写
void sFLASH_Config_Driver(void)
{
    uint8_t Temp_Buf[4];
	Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS3],0,Temp_Buf,1,0);
    DebugPrintf("[FLASH]Status register 3 : %02X\r\n",Temp_Buf[0]);
    if((Temp_Buf[0] & B01100000) != B01100000) //drv1,drv0
	{
		Temp_Buf[0] |= B01100000; //Output Driver Strength for max
		Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_ENABLE],0,NULL,0,0);
		Flash_Indirect_Operation(&Flash_Cmd[FLASH_CMD_WRITE_STATUS3],0,Temp_Buf,1,0);
		Flash_Auto_Polling_Operation(&Flash_Cmd[FLASH_CMD_READ_STATUS1],0x00000000,0x00000001,QSPI_PMM_AND,ENABLE,1,0);
        if((Temp_Buf[0] & B01100000) == B01100000)
        {
            DebugPrintf("[FLASH]status register 3 write fail: %02X\r\n",Temp_Buf[0]);
        }        
	}    
}
#if 0
#define FLASH_TEST_ADDR 0x20000
#define FLASH_TEST_LEN  0x4000 //bytes
uint32_t __ALIGNED(4) Flash_Write_buf[FLASH_TEST_LEN/4];
uint32_t __ALIGNED(4) Flash_Read_buf[FLASH_TEST_LEN/4];

void sFLASH_Test(void)
{
    uint64_t time;

//    DebugPrintf("[FLASH] XIP byte read\r\n");  
    DebugPrintf("[FLASH] XIP word read\r\n");  
    time = get_system_us();    
//    for(uint32_t i = 0; i < FLASH_TEST_LEN/sFLASH_SPI_SECTOR_SIZE;i++)
//        sFLASH_EraseSector(FLASH_TEST_ADDR + sFLASH_SPI_SECTOR_SIZE * i);
    sFLASH_EraseBlock64K(FLASH_TEST_ADDR);
    time = get_system_us() - time;
    DebugPrintf("[FLASH] Erase time =[%lld]us,speed = %dKB/s\r\n", time,FLASH_TEST_LEN*1000/time);   //FLASH_TEST_LEN*1000*1000/time/1000
    
//    for(uint32_t i = 0; i < FLASH_TEST_LEN;i++)
//    {
//        Flash_Write_buf[i] = i;
//    }
    for(uint32_t i = 0; i < FLASH_TEST_LEN/4;i++)
    {
        Flash_Write_buf[i] = i;
    }    
    time = get_system_us();    
    sFLASH_WriteBuffer((uint8_t*)Flash_Write_buf,FLASH_TEST_ADDR,FLASH_TEST_LEN);
    time = get_system_us() - time;
    DebugPrintf("[FLASH] write time =[%lld]us,speed = %dKB/s\r\n", time,FLASH_TEST_LEN*1000/time);  

    memset(Flash_Read_buf,0,FLASH_TEST_LEN);
    time = get_system_us();    
    sFLASH_ReadBufferWithXip((uint8_t*)Flash_Read_buf,FLASH_TEST_ADDR,FLASH_TEST_LEN);
    time = get_system_us() - time;
    DebugPrintf("[FLASH] XIP read time =[%lld]us,speed = %dKB/s\r\n", time,FLASH_TEST_LEN*1000/time);  
    
//    for(uint32_t i = 0; i < FLASH_TEST_LEN;i++)
//    {
//        if(Flash_Write_buf[i] != Flash_Read_buf[i])
//        {
//            DebugPrintf("[FLASH] read Error! w[%d]=0x%x,r[%d]=0x%x\r\n", i,Flash_Write_buf[i],i,Flash_Read_buf[i]);  
//            break;
//        }
//    }
    for(uint32_t i = 0; i < FLASH_TEST_LEN/4;i++)
    {
        if(Flash_Write_buf[i] != Flash_Read_buf[i])
        {
            DebugPrintf("[FLASH] ==XIP read Error! w[%d]=0x%x,r[%d]=0x%x\r\n", i,Flash_Write_buf[i],i,Flash_Read_buf[i]);  
            break;
        }
    }    
    time = get_system_us();    
    sFLASH_ReadBuffer((uint8_t*)Flash_Read_buf,FLASH_TEST_ADDR,FLASH_TEST_LEN);
    time = get_system_us() - time;
    DebugPrintf("[FLASH] DMA read time =[%lld]us,speed = %dKB/s\r\n", time,FLASH_TEST_LEN*1000/time);  
    for(uint32_t i = 0; i < FLASH_TEST_LEN/4;i++)
    {
        if(Flash_Write_buf[i] != Flash_Read_buf[i])
        {
            DebugPrintf("[FLASH] ==DMA read Error! w[%d]=0x%x,r[%d]=0x%x\r\n", i,Flash_Write_buf[i],i,Flash_Read_buf[i]);  
            break;
        }
    }
 }
 #endif
/////////////////////////////////////////////end file///////////////////////////////////////////////

